"""
-- coding: utf-8 --
@Time : 2024/1/8
@Author : 张书译
@Describe: APP adb方法封装
"""

import os
import re
import subprocess


class Adb(object):
    """
    Adb对象
    """

    def __init__(self, serial=None, adb_server_host=None, adb_server_port=None):
        """init"""
        self.__adb_cmd = None
        self.default_serial = serial if serial else os.environ.get("ANDROID_SERIAL", None)
        self.adb_server_host = str(adb_server_host if adb_server_host else 'localhost')
        self.adb_server_port = str(adb_server_port if adb_server_port else '5037')
        self.adbHostPortOptions = []
        if self.adb_server_host not in ['localhost', '127.0.0.1']:
            self.adbHostPortOptions += ["-H", self.adb_server_host]
        if self.adb_server_port != '5037':
            self.adbHostPortOptions += ["-P", self.adb_server_port]

    def adb(self):
        """adb"""
        if self.__adb_cmd is None:
            if "ANDROID_HOME" in os.environ:
                filename = "adb.exe" if os.name == 'nt' else "adb"
                adb_cmd = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", filename)
                if not os.path.exists(adb_cmd):
                    raise EnvironmentError(
                        "Adb not found in $ANDROID_HOME path: %s." % os.environ["ANDROID_HOME"])
            else:
                import distutils
                if "spawn" not in dir(distutils):
                    import distutils.spawn
                adb_cmd = distutils.spawn.find_executable("adb")
                if adb_cmd:
                    adb_cmd = os.path.realpath(adb_cmd)
                else:
                    raise EnvironmentError("$ANDROID_HOME environment not set.")
            self.__adb_cmd = adb_cmd
        return self.__adb_cmd

    def cmd(self, *args, **kwargs):
        """adb command, add -s serial by default. return the subprocess.Popen object."""
        serial = self.devices()
        if serial:
            if " " in serial:  # TODO how to include special chars on command line
                serial = "'%s'" % serial
            return self.raw_cmd(*["-s", serial] + list(args))
        else:
            return self.raw_cmd(*args)

    def raw_cmd(self, *args):
        """adb command. return the subprocess.Popen object."""
        cmd_line = [self.adb()] + self.adbHostPortOptions + list(args)
        if os.name != "nt":
            cmd_line = [" ".join(cmd_line)]
        return subprocess.Popen(cmd_line, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    def shell(self, device_id, *args, **kwargs):
        """adb command, add -s serial by default. return the subprocess.Popen object."""
        serial = device_id
        self.cmd("shell", *args, **kwargs)
        if serial:
            if " " in serial:  # TODO how to include special chars on command line
                serial = "'%s'" % serial
            return self.raw_cmd(*["-s", serial] + list(args))
        else:
            return self.raw_cmd(*args)

    def devices(self):
        """get a dict of attached devices. key is the device serial, value is device name."""
        out = self.raw_cmd("devices").communicate()[0].decode("utf-8")
        match = "List of devices attached"
        index = out.find(match)
        if index < 0:
            raise EnvironmentError("adb is not working.")
        return list([s.split("\t")[0] for s in out[index + len(match):].strip().splitlines() if s.strip()])

    def forward(self, local_port, device_port):
        """adb port forward. return 0 if success, else non-zero."""
        return self.cmd("forward", "tcp:%d" % local_port, "tcp:%d" % device_port).wait()

    def getVersion(self):
        """
        获取版本信息
        """
        return self.version()

    def version(self):
        """adb version"""
        devicesList = []
        for i in self.devices():
            match = os.popen(f"adb -s {i} shell getprop ro.build.version.release")
            devicesDic = {"platformName": "Android", "platformVersion": match.read().split('\n')[0], "deviceName": i}
            devicesList.append(devicesDic)
        return devicesList

    @staticmethod
    def get_device(device_id, auto_mode=1):
        """get a dict of attached devices. key is the device serial, value is device name."""
        if auto_mode == 1:
            from uiautomator import Device
            d = Device(device_id)
        else:
            import uiautomator2 as u2
            Adb.init_u2(device_id)
            d = u2.connect_usb(serial=device_id)
        return d

    @staticmethod
    def init_u2(device_id):
        """初始化Uiautomator2"""
        os.system("python -m uiautomator2 init -s %s" % device_id)


adb = Adb()
